package top.lshaci.framework.file.fdfs.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.csource.common.MyException;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.TrackerServer;
import org.springframework.util.unit.DataSize;
import top.lshaci.framework.file.enums.FileErrorInfo;
import top.lshaci.framework.file.exception.FileDownloadException;
import top.lshaci.framework.file.exception.FileOperateException;
import top.lshaci.framework.file.exception.FileUploadException;
import top.lshaci.framework.file.fdfs.enums.FileFdfsErrorInfo;
import top.lshaci.framework.file.fdfs.exception.FileFdfsException;
import top.lshaci.framework.file.fdfs.pool.TrackerServerPool;
import top.lshaci.framework.file.fdfs.service.FdfsFileOperateService;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

/**
 * FdfsFileOperateServiceImpl
 *
 * @author lshaci
 * @since 1.0.9
 */
@Slf4j
@AllArgsConstructor
public class FdfsFileOperateServiceImpl implements FdfsFileOperateService {

    private final DataSize maxSize;

    private final TrackerServerPool trackerServerPool;

    @Override
    public String upload(InputStream inputStream, String extName) throws IOException {
        final int available = inputStream.available();
        if (available <= 0) {
            throw new FileUploadException(FileErrorInfo.size_is_empty);
        }

        log.debug("Upload size: {}, Max size: {}", available, maxSize);
        if (available > maxSize.toBytes()) {
            throw new FileUploadException(FileErrorInfo.exceed_limit);
        }

        TrackerServer trackerServer = null;
        try {
            trackerServer = trackerServerPool.borrowObject();
            StorageClient1 storageClient = new StorageClient1(trackerServer, null);

            // read available bytes
            byte[] fileBuff = new byte[inputStream.available()];
            inputStream.read(fileBuff, 0, fileBuff.length);

            // upload
            String path = storageClient.upload_file1(fileBuff, extName, null);

            if (StrUtil.isBlank(path)) {
                throw new FileUploadException(FileErrorInfo.upload_failed);
            }

            log.debug("Upload success, Path is: {}", path);
            return path;
        } catch (MyException e) {
            log.error(FileFdfsErrorInfo.file_server_connection_failed.getMsg(), e);
            throw new FileFdfsException(FileFdfsErrorInfo.file_server_connection_failed);
        } finally {
            trackerServerPool.returnObject(trackerServer);
        }
    }

    @Override
    public void delete(List<String> pathList) {
        if (CollUtil.isEmpty(pathList)) {
            log.warn("未指定需要删除的文件");
            return;
        }

        TrackerServer trackerServer = trackerServerPool.borrowObject();
        StorageClient1 storageClient = new StorageClient1(trackerServer, null);
        try {
            for (String path : pathList) {
                log.info("从FastDfs中删除文件: Path: {}", path);
                storageClient.delete_file1(path);
            }
        } catch (IOException | MyException e) {
            log.error(FileFdfsErrorInfo.file_delete_failed.getMsg(), e);
            throw new FileFdfsException(FileFdfsErrorInfo.file_delete_failed);
        } finally {
            trackerServerPool.returnObject(trackerServer);
        }
    }

    @Override
    public void write(String path, OutputStream outputStream) {
        TrackerServer trackerServer = trackerServerPool.borrowObject();
        StorageClient1 storageClient = new StorageClient1(trackerServer, null);

        if (StrUtil.isBlank(path)) {
            throw new FileOperateException(FileErrorInfo.path_is_blank);
        }

        try {
            // download file from fastdfs
            byte[] fileByte = storageClient.download_file1(path);
            // file not exist, throw exception
            if(ArrayUtil.isEmpty(fileByte)){
                log.error(FileErrorInfo.not_exist.getMsg() + ": {}", path);
                throw new FileDownloadException(FileErrorInfo.not_exist);
            }

            IoUtil.write(outputStream, false, fileByte);
        } catch (IOException | MyException e) {
            log.error(FileErrorInfo.fetch_failed.getMsg() + ": {}", path);
            throw new FileDownloadException(FileErrorInfo.fetch_failed);
        } finally {
            trackerServerPool.returnObject(trackerServer);
        }
    }
}
